package com.security.symmetry_encry;

import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;

/**
 * @ClassName DESTest
 * @Description PBE 对称加密
 * @Detail Password-based encryption（基于密码加密）。其特点在于口令由用户自己掌管，不借助任何物理媒体；
 *          采用随机数（这里我们叫做盐）杂凑多重加密等方法保证数据的安全性。是一种简便的加密方式。
 * @Author MyPC
 * @Date 2020/11/22
 * @Version 1.0
 */
public class PBETest {
    /**
     * 支持以下任意一种算法
     *
     * <pre>
     * PBEWithMD5AndDES
     * PBEWithMD5AndTripleDES
     * PBEWithSHA1AndDESede
     * PBEWithSHA1AndRC2_40
     * </pre>
     */
    public static final String ALGORITHM = "PBEWITHMD5andDES";

    public static void main(String[] args) throws Exception {
        String hello="123";
        String pass="123456";
        byte[] salt = initSalt();
        System.out.println("待加密:"+hello);
        byte[] encrypt = encrypt(hello.getBytes(), pass,salt);
        System.out.println("加密："+new BASE64Encoder().encode(encrypt));
        byte[] decrypt = decrypt(encrypt, pass, salt);
        System.out.println("解密："+new String(decrypt));
    }

    /**
     * 初始化盐
     * @return
     */
    public static byte[] initSalt(){
        byte[] salt=new byte[8];
        Random random = new Random();
        random.nextBytes(salt);
        return salt;
    }

    /**
     * 将初始密码转换成密钥
     * @param password
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static Key toKey(String password) throws Exception {
        PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        return keyFactory.generateSecret(pbeKeySpec);
    }

    /**
     * 加密
     * @param data 待解密的数据
     * @param password 初始密码
     * @param salt 盐
     * @return
     */
    public static byte[] encrypt(byte[] data,String password,byte[] salt) throws Exception {
        Key key = toKey(password);
        PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 100);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,key,pbeParameterSpec);
        return cipher.doFinal(data);
    }

    public static byte[] decrypt(byte[] data, String password,byte[] salt) throws Exception {
        Key key = toKey(password);
        PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 100);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE,key,pbeParameterSpec);
        return cipher.doFinal(data);
    }

}
